package com.example.sendmessage.server.dao;

import com.example.sendmessage.common.MqException;
import com.example.sendmessage.server.core.Binding;
import com.example.sendmessage.server.core.Exchange;
import com.example.sendmessage.server.core.Message;
import com.example.sendmessage.server.core.Queue;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

/**
 * 统一的持久化封装
 * 封装数据库与文件的持久化操作
 */
public class DiskDataCenter {
    private DataBaseManager dataBaseManager = new DataBaseManager();
    private MessageFileManager messageFileManager = new MessageFileManager();

    /**
     * 持久化操作初始化
     * @throws MqException 数据库初始化异常
     */
    public void init() throws MqException {
        dataBaseManager.init();
        messageFileManager.init();
    }

    /**
     * 创建交换机
     * @param exchange 插入的交换机
     */
    public void insertExchange(Exchange exchange) {
        dataBaseManager.insertExchange(exchange);
    }

    /**
     * 删除交换机
     * @param exchangeName 删除交换机的名字
     */
    public void deleteExchange(String exchangeName) {
        dataBaseManager.deleteExchange(exchangeName);
    }

    /**
     * 查询所有交换机
     * @return 所有交换机的集合
     */
    public List<Exchange> selectAllExchanges() {
        return dataBaseManager.selectAllExchanges();
    }

    /**
     * 创建队列
     * @param queue 创建的队列
     */
    public void insertQueue(Queue queue) throws IOException, MqException {
        dataBaseManager.insertQueue(queue);
        // 同时创建对应的消息持久化文件
        messageFileManager.createQueueFiles(queue.getName());
    }

    /**
     * 删除队列
     * @param queueName 删除的队列名
     */
    public void deleteQueue(String queueName) throws MqException {
        dataBaseManager.deleteQueue(queueName);
        // 同时删除消息持久化文件
        messageFileManager.deleteQueueFiles(queueName);
    }

    /**
     * 查询所有的队列
     * @return 所有队列的集合
     */
    public List<Queue> selectAllQueues() {
        return dataBaseManager.selectAllQueues();
    }

    /**
     * @param binding 绑定关系
     */
    public void insertBinding(Binding binding) {
        dataBaseManager.insertBinding(binding);
    }

    /**
     * 删除绑定关系
     * @param binding 绑定关系
     */
    public void deleteBinding(Binding binding) {
        dataBaseManager.deleteBinding(binding);
    }

    /**
     * @return 所有的绑定关系
     */
    public List<Binding> selectAllBindings() {
        return dataBaseManager.selectAllBindings();
    }

    /**
     * 创建消息持久化文件
     * @param queueName 队列名字
     * @throws MqException 目录创建失败的异常
     * @throws IOException 文件创建失败的异常
     */
    public void createQueueFiles(String queueName) throws IOException, MqException {
        messageFileManager.createQueueFiles(queueName);
    }

    /**
     * 删除消息持久化文件
     * @param queueName 队列名
     * @throws MqException 删除文件失败异常
     */
    public void deleteQueueFiles(String queueName) throws MqException {
        messageFileManager.deleteQueueFiles(queueName);
    }

    /**
     * 将消息写入文件进行持久化存储
     * @param queue 需要消息持久化的队列队列
     * @param message 需要持久化的消息
     * @throws MqException 文件是否存在
     * @throws IOException 写入文件流的异常
     */
    public void sendMessage(Queue queue, Message message) throws IOException, MqException {
        messageFileManager.sendMessage(queue, message);
    }

    /**
     * 删除持久化的消息，更改状态的方式
     * @param queue 队列
     * @param message 消息
     * @throws IOException 随机读取文件异常
     * @throws ClassNotFoundException 序列化异常
     */
    public void deleteMessage(Queue queue, Message message) throws IOException, ClassNotFoundException, MqException {
        messageFileManager.deleteMessage(queue, message);
        // 每次删除都判断一下是否gc
        if (messageFileManager.checkGC(queue.getName())) {
            // 满足gc条件就gc
            messageFileManager.gc(queue);
        }
    }

    /**
     * 消息可靠性，保证宕机也能将数据重新加载
     * @param queueName 队列名
     * @return 消息链表，存放有效地消息
     * @throws IOException 文件流异常
     * @throws MqException 文件读取时格式不匹配
     * @throws ClassNotFoundException 序列化异常
     */
    public LinkedList<Message> loadAllMessageFromQueue(String queueName) throws IOException, MqException, ClassNotFoundException {
        return messageFileManager.loadAllMessagesFromQueue(queueName);
    }
}
